home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Net / Socket.php < prev    next >
Encoding:
PHP Script  |  2005-07-07  |  15.0 KB  |  529 lines

  1. <?php
  2. //
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.0 of the PHP license,       |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Stig Bakken <ssb@php.net>                                   |
  17. // |          Chuck Hagenbuch <chuck@horde.org>                           |
  18. // +----------------------------------------------------------------------+
  19. //
  20. // $Id: Socket.php,v 1.24 2005/02/03 20:40:16 chagenbu Exp $
  21.  
  22. require_once 'PEAR.php';
  23.  
  24. define('NET_SOCKET_READ',  1);
  25. define('NET_SOCKET_WRITE', 2);
  26. define('NET_SOCKET_ERROR', 3);
  27.  
  28. /**
  29.  * Generalized Socket class.
  30.  *
  31.  * @version 1.1
  32.  * @author Stig Bakken <ssb@php.net>
  33.  * @author Chuck Hagenbuch <chuck@horde.org>
  34.  */
  35. class Net_Socket extends PEAR {
  36.  
  37.     /**
  38.      * Socket file pointer.
  39.      * @var resource $fp
  40.      */
  41.     var $fp = null;
  42.  
  43.     /**
  44.      * Whether the socket is blocking. Defaults to true.
  45.      * @var boolean $blocking
  46.      */
  47.     var $blocking = true;
  48.  
  49.     /**
  50.      * Whether the socket is persistent. Defaults to false.
  51.      * @var boolean $persistent
  52.      */
  53.     var $persistent = false;
  54.  
  55.     /**
  56.      * The IP address to connect to.
  57.      * @var string $addr
  58.      */
  59.     var $addr = '';
  60.  
  61.     /**
  62.      * The port number to connect to.
  63.      * @var integer $port
  64.      */
  65.     var $port = 0;
  66.  
  67.     /**
  68.      * Number of seconds to wait on socket connections before assuming
  69.      * there's no more data. Defaults to no timeout.
  70.      * @var integer $timeout
  71.      */
  72.     var $timeout = false;
  73.  
  74.     /**
  75.      * Number of bytes to read at a time in readLine() and
  76.      * readAll(). Defaults to 2048.
  77.      * @var integer $lineLength
  78.      */
  79.     var $lineLength = 2048;
  80.  
  81.     /**
  82.      * Connect to the specified port. If called when the socket is
  83.      * already connected, it disconnects and connects again.
  84.      *
  85.      * @param string  $addr        IP address or host name.
  86.      * @param integer $port        TCP port number.
  87.      * @param boolean $persistent  (optional) Whether the connection is
  88.      *                             persistent (kept open between requests
  89.      *                             by the web server).
  90.      * @param integer $timeout     (optional) How long to wait for data.
  91.      * @param array   $options     See options for stream_context_create.
  92.      *
  93.      * @access public
  94.      *
  95.      * @return boolean | PEAR_Error  True on success or a PEAR_Error on failure.
  96.      */
  97.     function connect($addr, $port = 0, $persistent = null, $timeout = null, $options = null)
  98.     {
  99.         if (is_resource($this->fp)) {
  100.             @fclose($this->fp);
  101.             $this->fp = null;
  102.         }
  103.  
  104.         if (!$addr) {
  105.             return $this->raiseError('$addr cannot be empty');
  106.         } elseif (strspn($addr, '.0123456789') == strlen($addr) ||
  107.                   strstr($addr, '/') !== false) {
  108.             $this->addr = $addr;
  109.         } else {
  110.             $this->addr = @gethostbyname($addr);
  111.         }
  112.  
  113.         $this->port = $port % 65536;
  114.  
  115.         if ($persistent !== null) {
  116.             $this->persistent = $persistent;
  117.         }
  118.  
  119.         if ($timeout !== null) {
  120.             $this->timeout = $timeout;
  121.         }
  122.  
  123.         $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen';
  124.         $errno = 0;
  125.         $errstr = '';
  126.         if ($options && function_exists('stream_context_create')) {
  127.             if ($this->timeout) {
  128.                 $timeout = $this->timeout;
  129.             } else {
  130.                 $timeout = 0;
  131.             }
  132.             $context = stream_context_create($options);
  133.             $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context);
  134.         } else {
  135.             if ($this->timeout) {
  136.                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout);
  137.             } else {
  138.                 $fp = @$openfunc($this->addr, $this->port, $errno, $errstr);
  139.             }
  140.         }
  141.  
  142.         if (!$fp) {
  143.             return $this->raiseError($errstr, $errno);
  144.         }
  145.  
  146.         $this->fp = $fp;
  147.  
  148.         return $this->setBlocking($this->blocking);
  149.     }
  150.  
  151.     /**
  152.      * Disconnects from the peer, closes the socket.
  153.      *
  154.      * @access public
  155.      * @return mixed true on success or an error object otherwise
  156.      */
  157.     function disconnect()
  158.     {
  159.         if (!is_resource($this->fp)) {
  160.             return $this->raiseError('not connected');
  161.         }
  162.  
  163.         @fclose($this->fp);
  164.         $this->fp = null;
  165.         return true;
  166.     }
  167.  
  168.     /**
  169.      * Find out if the socket is in blocking mode.
  170.      *
  171.      * @access public
  172.      * @return boolean  The current blocking mode.
  173.      */
  174.     function isBlocking()
  175.     {
  176.         return $this->blocking;
  177.     }
  178.  
  179.     /**
  180.      * Sets whether the socket connection should be blocking or
  181.      * not. A read call to a non-blocking socket will return immediately
  182.      * if there is no data available, whereas it will block until there
  183.      * is data for blocking sockets.
  184.      *
  185.      * @param boolean $mode  True for blocking sockets, false for nonblocking.
  186.      * @access public
  187.      * @return mixed true on success or an error object otherwise
  188.      */
  189.     function setBlocking($mode)
  190.     {
  191.         if (!is_resource($this->fp)) {
  192.             return $this->raiseError('not connected');
  193.         }
  194.  
  195.         $this->blocking = $mode;
  196.         socket_set_blocking($this->fp, $this->blocking);
  197.         return true;
  198.     }
  199.  
  200.     /**
  201.      * Sets the timeout value on socket descriptor,
  202.      * expressed in the sum of seconds and microseconds
  203.      *
  204.      * @param integer $seconds  Seconds.
  205.      * @param integer $microseconds  Microseconds.
  206.      * @access public
  207.      * @return mixed true on success or an error object otherwise
  208.      */
  209.     function setTimeout($seconds, $microseconds)
  210.     {
  211.         if (!is_resource($this->fp)) {
  212.             return $this->raiseError('not connected');
  213.         }
  214.  
  215.         return socket_set_timeout($this->fp, $seconds, $microseconds);
  216.     }
  217.  
  218.     /**
  219.      * Returns information about an existing socket resource.
  220.      * Currently returns four entries in the result array:
  221.      *
  222.      * <p>
  223.      * timed_out (bool) - The socket timed out waiting for data<br>
  224.      * blocked (bool) - The socket was blocked<br>
  225.      * eof (bool) - Indicates EOF event<br>
  226.      * unread_bytes (int) - Number of bytes left in the socket buffer<br>
  227.      * </p>
  228.      *
  229.      * @access public
  230.      * @return mixed Array containing information about existing socket resource or an error object otherwise
  231.      */
  232.     function getStatus()
  233.     {
  234.         if (!is_resource($this->fp)) {
  235.             return $this->raiseError('not connected');
  236.         }
  237.  
  238.         return socket_get_status($this->fp);
  239.     }
  240.  
  241.     /**
  242.      * Get a specified line of data
  243.      *
  244.      * @access public
  245.      * @return $size bytes of data from the socket, or a PEAR_Error if
  246.      *         not connected.
  247.      */
  248.     function gets($size)
  249.     {
  250.         if (!is_resource($this->fp)) {
  251.             return $this->raiseError('not connected');
  252.         }
  253.  
  254.         return @fgets($this->fp, $size);
  255.     }
  256.  
  257.     /**
  258.      * Read a specified amount of data. This is guaranteed to return,
  259.      * and has the added benefit of getting everything in one fread()
  260.      * chunk; if you know the size of the data you're getting
  261.      * beforehand, this is definitely the way to go.
  262.      *
  263.      * @param integer $size  The number of bytes to read from the socket.
  264.      * @access public
  265.      * @return $size bytes of data from the socket, or a PEAR_Error if
  266.      *         not connected.
  267.      */
  268.     function read($size)
  269.     {
  270.         if (!is_resource($this->fp)) {
  271.             return $this->raiseError('not connected');
  272.         }
  273.  
  274.         return @fread($this->fp, $size);
  275.     }
  276.  
  277.     /**
  278.      * Write a specified amount of data.
  279.      *
  280.      * @param string  $data       Data to write.
  281.      * @param integer $blocksize  Amount of data to write at once.
  282.      *                            NULL means all at once.
  283.      *
  284.      * @access public
  285.      * @return mixed true on success or an error object otherwise
  286.      */
  287.     function write($data, $blocksize = null)
  288.     {
  289.         if (!is_resource($this->fp)) {
  290.             return $this->raiseError('not connected');
  291.         }
  292.  
  293.         if (is_null($blocksize) && !OS_WINDOWS) {
  294.             return fwrite($this->fp, $data);
  295.         } else {
  296.             if (is_null($blocksize)) {
  297.                 $blocksize = 1024;
  298.             }
  299.  
  300.             $pos = 0;
  301.             $size = strlen($data);
  302.             while ($pos < $size) {
  303.                 $written = @fwrite($this->fp, substr($data, $pos, $blocksize));
  304.                 if ($written === false) {
  305.                     return false;
  306.                 }
  307.                 $pos += $written;
  308.             }
  309.  
  310.             return $pos;
  311.         }
  312.     }
  313.  
  314.     /**
  315.      * Write a line of data to the socket, followed by a trailing "\r\n".
  316.      *
  317.      * @access public
  318.      * @return mixed fputs result, or an error
  319.      */
  320.     function writeLine($data)
  321.     {
  322.         if (!is_resource($this->fp)) {
  323.             return $this->raiseError('not connected');
  324.         }
  325.  
  326.         return fwrite($this->fp, $data . "\r\n");
  327.     }
  328.  
  329.     /**
  330.      * Tests for end-of-file on a socket descriptor.
  331.      *
  332.      * @access public
  333.      * @return bool
  334.      */
  335.     function eof()
  336.     {
  337.         return (is_resource($this->fp) && feof($this->fp));
  338.     }
  339.  
  340.     /**
  341.      * Reads a byte of data
  342.      *
  343.      * @access public
  344.      * @return 1 byte of data from the socket, or a PEAR_Error if
  345.      *         not connected.
  346.      */
  347.     function readByte()
  348.     {
  349.         if (!is_resource($this->fp)) {
  350.             return $this->raiseError('not connected');
  351.         }
  352.  
  353.         return ord(@fread($this->fp, 1));
  354.     }
  355.  
  356.     /**
  357.      * Reads a word of data
  358.      *
  359.      * @access public
  360.      * @return 1 word of data from the socket, or a PEAR_Error if
  361.      *         not connected.
  362.      */
  363.     function readWord()
  364.     {
  365.         if (!is_resource($this->fp)) {
  366.             return $this->raiseError('not connected');
  367.         }
  368.  
  369.         $buf = @fread($this->fp, 2);
  370.         return (ord($buf[0]) + (ord($buf[1]) << 8));
  371.     }
  372.  
  373.     /**
  374.      * Reads an int of data
  375.      *
  376.      * @access public
  377.      * @return integer  1 int of data from the socket, or a PEAR_Error if
  378.      *                  not connected.
  379.      */
  380.     function readInt()
  381.     {
  382.         if (!is_resource($this->fp)) {
  383.             return $this->raiseError('not connected');
  384.         }
  385.  
  386.         $buf = @fread($this->fp, 4);
  387.         return (ord($buf[0]) + (ord($buf[1]) << 8) +
  388.                 (ord($buf[2]) << 16) + (ord($buf[3]) << 24));
  389.     }
  390.  
  391.     /**
  392.      * Reads a zero-terminated string of data
  393.      *
  394.      * @access public
  395.      * @return string, or a PEAR_Error if
  396.      *         not connected.
  397.      */
  398.     function readString()
  399.     {
  400.         if (!is_resource($this->fp)) {
  401.             return $this->raiseError('not connected');
  402.         }
  403.  
  404.         $string = '';
  405.         while (($char = @fread($this->fp, 1)) != "\x00")  {
  406.             $string .= $char;
  407.         }
  408.         return $string;
  409.     }
  410.  
  411.     /**
  412.      * Reads an IP Address and returns it in a dot formated string
  413.      *
  414.      * @access public
  415.      * @return Dot formated string, or a PEAR_Error if
  416.      *         not connected.
  417.      */
  418.     function readIPAddress()
  419.     {
  420.         if (!is_resource($this->fp)) {
  421.             return $this->raiseError('not connected');
  422.         }
  423.  
  424.         $buf = @fread($this->fp, 4);
  425.         return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]),
  426.                        ord($buf[2]), ord($buf[3]));
  427.     }
  428.  
  429.     /**
  430.      * Read until either the end of the socket or a newline, whichever
  431.      * comes first. Strips the trailing newline from the returned data.
  432.      *
  433.      * @access public
  434.      * @return All available data up to a newline, without that
  435.      *         newline, or until the end of the socket, or a PEAR_Error if
  436.      *         not connected.
  437.      */
  438.     function readLine()
  439.     {
  440.         if (!is_resource($this->fp)) {
  441.             return $this->raiseError('not connected');
  442.         }
  443.  
  444.         $line = '';
  445.         $timeout = time() + $this->timeout;
  446.         while (!feof($this->fp) && (!$this->timeout || time() < $timeout)) {
  447.             $line .= @fgets($this->fp, $this->lineLength);
  448.             if (substr($line, -1) == "\n") {
  449.                 return rtrim($line, "\r\n");
  450.             }
  451.         }
  452.         return $line;
  453.     }
  454.  
  455.     /**
  456.      * Read until the socket closes, or until there is no more data in
  457.      * the inner PHP buffer. If the inner buffer is empty, in blocking
  458.      * mode we wait for at least 1 byte of data. Therefore, in
  459.      * blocking mode, if there is no data at all to be read, this
  460.      * function will never exit (unless the socket is closed on the
  461.      * remote end).
  462.      *
  463.      * @access public
  464.      *
  465.      * @return string  All data until the socket closes, or a PEAR_Error if
  466.      *                 not connected.
  467.      */
  468.     function readAll()
  469.     {
  470.         if (!is_resource($this->fp)) {
  471.             return $this->raiseError('not connected');
  472.         }
  473.  
  474.         $data = '';
  475.         while (!feof($this->fp)) {
  476.             $data .= @fread($this->fp, $this->lineLength);
  477.         }
  478.         return $data;
  479.     }
  480.  
  481.     /**
  482.      * Runs the equivalent of the select() system call on the socket
  483.      * with a timeout specified by tv_sec and tv_usec.
  484.      *
  485.      * @param integer $state    Which of read/write/error to check for.
  486.      * @param integer $tv_sec   Number of seconds for timeout.
  487.      * @param integer $tv_usec  Number of microseconds for timeout.
  488.      *
  489.      * @access public
  490.      * @return False if select fails, integer describing which of read/write/error
  491.      *         are ready, or PEAR_Error if not connected.
  492.      */
  493.     function select($state, $tv_sec, $tv_usec = 0)
  494.     {
  495.         if (!is_resource($this->fp)) {
  496.             return $this->raiseError('not connected');
  497.         }
  498.  
  499.         $read = null;
  500.         $write = null;
  501.         $except = null;
  502.         if ($state & NET_SOCKET_READ) {
  503.             $read[] = $this->fp;
  504.         }
  505.         if ($state & NET_SOCKET_WRITE) {
  506.             $write[] = $this->fp;
  507.         }
  508.         if ($state & NET_SOCKET_ERROR) {
  509.             $except[] = $this->fp;
  510.         }
  511.         if (false === ($sr = stream_select($read, $write, $except, $tv_sec, $tv_usec))) {
  512.             return false;
  513.         }
  514.  
  515.         $result = 0;
  516.         if (count($read)) {
  517.             $result |= NET_SOCKET_READ;
  518.         }
  519.         if (count($write)) {
  520.             $result |= NET_SOCKET_WRITE;
  521.         }
  522.         if (count($except)) {
  523.             $result |= NET_SOCKET_ERROR;
  524.         }
  525.         return $result;
  526.     }
  527.  
  528. }
  529.